#include "clientwindow.h"

#include <QApplication>
#include <QMessageBox>
#include <QSettings>
#include <QStatusBar>
#include <QTemporaryFile>

// Local Includes
#include "clientnetengine.h"
#include "connectreplymsg.h"
#include "clientconnection.h"
#include "clientnetengine.h"
#include "netmsg.h"
#include "configdlg.h"
#include "configkeys.h"
#include "processupdatemsg.h"
#include "resultsmsg.h"
#include "scanresults.h"

/////////////////////////////////////////////////////////////////////
// Construction & Destruction
/////////////////////////////////////////////////////////////////////
CClientWindow::CClientWindow(QWidget *pParent/* = NULL*/, Qt::WFlags windowFlags/* = 0*/)
	: QMainWindow(pParent, windowFlags),
	  m_pClientConnection(new CClientConnection(this)),
	  m_pScanResults(NULL)
{
	setupUi(this);
	m_pScanResultsWidget->setVisible(false);

	// Signals & Slots.
	connect(m_pExitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
	connect(m_pAboutAction, SIGNAL(triggered()), this, SLOT(onAbout()));
	connect(m_pAboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));

	connect(m_pClientConnection, SIGNAL(connected()), this, SLOT(onClientConnected()));
	connect(m_pClientConnection, SIGNAL(connectFailed(quint32,QString)), this, SLOT(onConnectFailed(quint32,QString)));

	connect(m_pConfigWidget, SIGNAL(sendProject(QPair<QString,QStringList>,QString)), this,
			SLOT(onConfigWidgetSendProject(QPair<QString,QStringList>,QString)));
	connect(action_Configure_Client, SIGNAL(triggered()), this, SLOT(onConfigureClient()));

	connect(btnConnect, SIGNAL(clicked()), this, SLOT(tryConnect()));
	connect(btnConfigure, SIGNAL(clicked()), this, SLOT(onConfigureClient()));

	// hide config and retry buttons:
	btnConnect->hide();
	btnConfigure->hide();

	// load settings:
	QSettings s;

	// if the user hasn't configured anything yet, show the config dialog now:
	if (!s.childKeys().contains(K_SERVER_ADDR))
	{
		show();
		CConfigDlg dlg(this);
		// TODO - make sure the user pressed OK?
		dlg.exec();
	}

	tryConnect();
}

CClientWindow::~CClientWindow()
{
	delete m_pScanResults;
}

/////////////////////////////////////////////////////////////////////
// Private Slots
/////////////////////////////////////////////////////////////////////
void CClientWindow::onAbout()
{
	QMessageBox::about(this, "About Client", "<b>Version 1.0.0.0</b><br/>&copy; Thomi Richards & Kirk Larkin");
}

void CClientWindow::onClientConnected()
{
	setStatusTip("Connected");
	// Now we know the clientEngine has been created, we can hook up to it.
	connect(m_pClientConnection->GetClientNetEngine(), SIGNAL(newMessage()), this, SLOT(onClientNewMessage()));

	// Let's "register" with the server.
	m_pClientConnection->connectToServer("UserName", "PasswordHash");
}

void CClientWindow::onClientNewMessage()
{
	CNetMsg *pMsg = m_pClientConnection->GetClientNetEngine()->getMessage();

	if (pMsg)
	{
		switch(pMsg->getType())
		{
			case CNetMsg::MSG_TYPE_CONNECT_REPLY:
			{
				// The reply from the server will contain the pluginManager config.
				// For now, we show this in the UI.
				const CConnectReplyMsg *const pReplyMsg = static_cast<CConnectReplyMsg*>(pMsg);

				if(pReplyMsg)
				{
					m_pConfigWidget->setConfigPayload(pReplyMsg->getConfigPayload());

					// Update the Ui to show we *might* have some plugins.
					stackedWidget->setCurrentIndex(1);
				}
				break;
			}

			case CNetMsg::MSG_TYPE_PROC_UPDATE:
			{
				CProcessUpdateMsg *pUpdateMsg = static_cast<CProcessUpdateMsg*>(pMsg);
				if (pUpdateMsg)
				{
					serverProgress->setMaximum(pUpdateMsg->getTotal());
					serverProgress->setValue(pUpdateMsg->getCurrent());
					progressHint->addItem(pUpdateMsg->getMessage());
					progressHint->scrollToBottom();
				}
			}
			break;

			case CNetMsg::MSG_TYPE_RESULTS:
			{
				QString strResultsFilePath;
				CResultsMsg *pResultsMsg = static_cast<CResultsMsg*>(pMsg);
				QTemporaryFile f;
				f.setAutoRemove(false);
				f.open();
				f.write(pResultsMsg->getResultsData());
				qDebug() << "Results file is at: " << f.fileName();
				strResultsFilePath = f.fileName();
				f.close();

				delete m_pScanResults; m_pScanResults = NULL;
				m_pScanResults = new CScanResults(strResultsFilePath);
				m_pScanResultsWidget->setScanResults(m_pScanResults);

				m_pScanResultsWidget->setVisible(true);

				if(QMessageBox::question(this, tr("View Results"), tr("The project scan has completed. Would you like "
						"to view the results now?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)
						== QMessageBox::Yes)
				{
					tabWidget->setCurrentIndex(2);
				}
			}
			break;

			default:
				break;
		}

		delete pMsg;
	}
}

void CClientWindow::onConfigWidgetSendProject(const QPair<QString, QStringList> &theFileCollection,
		const QString &strConfigPayload)
{
	m_pClientConnection->GetClientNetEngine()->sendProject(theFileCollection, strConfigPayload);
	stackedWidget->setCurrentIndex(2);
}
/////////////////////////////////////////////////////////////////////

void CClientWindow::onConfigureClient()
{
	CConfigDlg dlg(this);
	dlg.exec();
}

void CClientWindow::tryConnect()
{
	QSettings s;
	// Automatically connect on startup.
	// This will run on a seperate thread.
	QString strServer = s.value(K_SERVER_ADDR).toString();
	quint32 nPort = s.value(K_SERVER_PORT).toUInt();

	QString strMsg = QString("Connecting to '%1:%2'").arg(strServer).arg(nPort);

	setStatusTip(strMsg);
	connectLabel->setText(strMsg);
	m_pClientConnection->connectToHost(strServer , nPort);
	// since we're connecting, make sure that the retry and config buttons are hidden from sight:
	btnConnect->hide();
	btnConfigure->hide();
	connectProgress->show();
}


void CClientWindow::onConnectFailed(quint32 nError, const QString &strErrorMessage)
{
	Q_UNUSED(nError);
	qDebug() << Q_FUNC_INFO << strErrorMessage;
	QString strMsg = QString("Connection failed: %1").arg(strErrorMessage);

	setStatusTip(strMsg);
	connectLabel->setText(strMsg);

	// connect failed. Hide propgress bar and show retry and config buttons:
	btnConnect->show();
	btnConfigure->show();
	connectProgress->hide();
}

